<html>
<head><meta charset="utf-8"><title>fn item &quot;outlives bounds&quot; · general · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/index.html">general</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html">fn item &quot;outlives bounds&quot;</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="247687638"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/fn%20item%20%22outlives%20bounds%22/near/247687638" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html#247687638">(Jul 30 2021 at 09:45)</a>:</h4>
<p>For context, this started off <a href="https://users.rust-lang.org/t/a-problem-about-lifetime-pls-help/62426/12?u=yandros">https://users.rust-lang.org/t/a-problem-about-lifetime-pls-help/62426/12?u=yandros</a>, but since it's getting clearly out of depth regarding the OP, let's follow the discussion here, since I'd be curious to hear what <span class="user-mention" data-user-id="116009">@nikomatsakis</span> (or other people knowledgeable of the compiler lifetime bounds) have to say about it:</p>
<p>So, the thing is, that while a higher-order function item or pointer (both work) can be <code>'static</code> without any issue whatsoever (as expected, I'd say); things start to be a bit weird once we deal with non-higher-order stuff.</p>
<p>Mainly, I have ended up observing the following <em>empirical</em> "rules":</p>
<blockquote>
<ul>
<li>a function item / ZST which is only generic over lifetimes, does not seem to have its type "visibly" infected with the (potentially non-higher-order) lifetime of its parameter, thus avoiding the case of "if all type/lifetime parameters appearing in the type <code>T</code> must outlive <code>'a</code> , then <code>T : 'a</code>"</li>
</ul>
<p>Any other case:</p>
<ul>
<li>be it a function item which was generic over types and which gets turbofish-fed an actual lifetime-infected type,</li>
<li>be it a non-higher-order function pointer,</li>
<li>be it a trait object,</li>
<li>be it an existential type,</li>
</ul>
<p>they all get infected with the lifetime in the classical way which thus constrains them not to outlive that lifetime.</p>
</blockquote>
<ul>
<li><a href="https://rust.godbolt.org/z/sE8evocKd">Godbolt</a></li>
</ul>
<p>Note that all the constrained cases make sense, to me, once we read the relevant RFC (<a href="https://rust-lang.github.io/rfcs/1214-projections-lifetimes-and-wf.html">https://rust-lang.github.io/rfcs/1214-projections-lifetimes-and-wf.html</a>): a generic type is constrained not to outlive any of its parameters.<br>
The higher order function item case, as quinedot pointed out on URLO, makes sense as well, since a higher-order lifetime does not introduce an outlives bound (which one would it be?).<br>
The intriguing case is the non-higher-order function item case (<em>e.g.</em>, <code>foo::&lt;'non_static&gt;</code> below).</p>
<hr>
<p>So, for instance, while a non-higher order implementor of <code>'static + FnOnce(&amp;'non_static ())</code> can exist (the function item I was referring to), returning an <code>-&gt; impl 'static + FnOnce(&amp;'non_static ())</code> existential type is kind of a lie, since the returned thing will be constrained not to outlive <code>'non_static</code>.<br>
This leads to an interesting and surprising example:<br>
an <code>(impl 'static + FnOnce(&amp;'non_static ())) -&gt; impl 'static + FnOnce(&amp;'non_static ())</code> function cannot be composed with itself!</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">_with_non_static</span><span class="o">&lt;'</span><span class="na">non_static</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">funnel</span><span class="o">&lt;'</span><span class="na">lt</span><span class="w"> </span>: <span class="o">'</span><span class="na">lt</span><span class="o">&gt;</span><span class="p">(</span><span class="w"></span>
<span class="w">        </span><span class="n">f</span>: <span class="nc">impl</span><span class="w"> </span><span class="o">'</span><span class="nb">static</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">FnOnce</span><span class="p">(</span><span class="o">&amp;'</span><span class="na">lt</span><span class="w"> </span><span class="p">()),</span><span class="w"></span>
<span class="w">    </span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">impl</span><span class="w"> </span><span class="o">'</span><span class="nb">static</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">FnOnce</span><span class="p">(</span><span class="o">&amp;'</span><span class="na">lt</span><span class="w"> </span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// &lt;- Actually not `'static` in practice</span>
<span class="w">                                          </span><span class="c1">//    because `'lt`-infected existential!</span>
<span class="w">        </span><span class="n">f</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="o">&lt;'</span><span class="na">lt</span><span class="w"> </span>: <span class="o">'</span><span class="na">lt</span><span class="o">&gt;</span><span class="p">(</span><span class="n">_</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">lt</span> <span class="p">())</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">funnel</span>::<span class="o">&lt;'</span><span class="na">non_static</span><span class="o">&gt;</span><span class="p">(</span><span class="n">foo</span>::<span class="o">&lt;'</span><span class="na">non_static</span><span class="o">&gt;</span><span class="p">);</span><span class="w"> </span><span class="c1">// OK</span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">funnel</span>::<span class="o">&lt;'</span><span class="na">non_static</span><span class="o">&gt;</span><span class="p">(</span><span class="n">f</span><span class="p">);</span><span class="w"> </span><span class="c1">// Fails!?</span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<ul>
<li><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=c53b3b7640566ece49bf177937878c1d">Playground</a></li>
</ul>



<a name="247695208"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/fn%20item%20%22outlives%20bounds%22/near/247695208" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Giacomo Stevanato <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html#247695208">(Jul 30 2021 at 11:23)</a>:</h4>
<p>I think this might be a problem with how outlives constraints are resolved for opaque types. The RFC also seems to not mention opaque types</p>



<a name="247696344"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/fn%20item%20%22outlives%20bounds%22/near/247696344" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Giacomo Stevanato <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html#247696344">(Jul 30 2021 at 11:37)</a>:</h4>
<p>The outlive predicate seems to originate <a href="https://github.com/rust-lang/rust/blob/f739552870cdb23d433478739b371f22b155af8a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs#L104-L111">here</a>, then <code>type_must_outlive</code> ends up calling <code>TyCtxt::push_outlives_components</code>, which in turn calls <code>compute_components</code> <a href="https://github.com/rust-lang/rust/blob/f739552870cdb23d433478739b371f22b155af8a/compiler/rustc_middle/src/ty/outlives.rs#L60-L189">here</a> which seems to just to extend the bound to all the generics of the function it is defined on, which include the <code>'lt</code>. It's kind of unfortunate how the generic of the function are always included in the opaque type without a way to opt out.</p>



<a name="247757989"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/fn%20item%20%22outlives%20bounds%22/near/247757989" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Quine Dot <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html#247757989">(Jul 30 2021 at 20:31)</a>:</h4>
<p>This behavior of <code>impl Trait</code> in return position is apparently specified <a href="https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#scoping-for-type-and-lifetime-parameters">in RFC 1951</a>.  Issues <a href="https://github.com/rust-lang/rust/issues/79415">79415</a> and <a href="https://github.com/rust-lang/rust/issues/82171">82171</a> are also about this, where <span class="user-mention" data-user-id="119031">@Esteban Küber</span> says</p>
<blockquote>
<p>There's no way currently to express that an <code>impl Trait</code> doesn't capture all the input lifetimes. Once <code>type Ret&lt;'a&gt; = impl Trait + 'a;</code> is stabilized you could express the behavior you're looking for, but for now the only option are the ones identified in the report (explicit type and <code>Box&lt;dyn Trait&gt;</code>).</p>
</blockquote>
<p>(At least some of the confusion stems from the timing of all this.  <a href="https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md"><code>impl Trait</code> in return position</a> was introduced after RFC 1214; moreover, it wasn't really adequately specified until RFC 1951.  There's also no consolidated documentation around any of this that I have found.)</p>



<a name="247766070"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/fn%20item%20%22outlives%20bounds%22/near/247766070" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Quine Dot <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/fn.20item.20.22outlives.20bounds.22.html#247766070">(Jul 30 2021 at 21:44)</a>:</h4>
<p>The <a href="https://github.com/rust-lang/rust/issues/82171">second issue</a> mentioned above uses a <a href="https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999"><code>Captures</code> workaround</a> related to <a href="https://doc.rust-lang.org/stable/error-index.html#E0700">E0700</a>.  That's an entrance to a rather deep rabbit hole innvolving <code>impl Trait</code> lifetime captures.  I was going to summarize it, but in the process found that <a href="https://crates.io/crates/fix-hidden-lifetime-bug">you're already quite aware</a>, so I'll skip it.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>